/* * * * * * * * * * * * * * * * * * * * * * * *
 * Author: Thai Vong
 * Created on: May 3rd 2007
 * Last Modified by: Thanh Pham
 * Last Modified on: May 29th 2007
 * Last Modified by: Ho Huynh
 * Last Modified on: Nov 13th 2008
 * * * * * * * * * * * * * * * * * * * * * * * */
using System;
using System.Windows.Forms;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;

using DevExpress.Utils;
using DevExpress.XtraGrid;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.XtraBars;
using DevExpress.XtraBars.Controls;
using PharmacyPharnet.Core.Entity;
using PharmacyPharnet.Core.CustomEventArgs;
using Pharmacy.Data.Entity;
using Pharmacy.Ultilities.Resources;
using Pharmacy.Ultilities;
using Pharmacy.Business;



namespace PharmacyPharnet.Core
{
    /// <summary>
    /// Summary description for ModuleManager.
    /// </summary>
    public class ViewManager
    {
        #region declare
        private const string KEY_REFRESH_ACTIVE = "RefreshActive_{0}";
        private static TypeInfoCollection _typeInfoCollection = null;
        private static ControlViewBase _currentControlView = null;
        private static PharmacyPharnet.Core.Entity.TypeInfo _currentTypeInfo = null;

        private static Control _parent = null;
        private static WaitDialogForm _waitingDialog = null;

        private static Dictionary<string, IView> _ListWindows = new Dictionary<string, IView>();

        private static string _FeatureTypeNameInDialog = string.Empty;

        #endregion

        #region Constructor

        //static ViewManager() {
        //    InitializeTypeInfo();
        //}

        private ViewManager() { }

        #endregion

        #region Event
        public static event EventHandler<WindowEventArgs> WindowChanged;
        private static void OnWindowChanged(WindowEventArgs e)
        {
            if (WindowChanged != null)
            {
                WindowChanged(null, e);
            }
        }

        #endregion

        #region Public methods

        /// <summary>
        /// Set the container control. It can be a Panel or the devexpress groupcontrol
        /// </summary>
        /// <value>The parent control object.</value>
        public static Control Parent
        {
            set
            {
                _parent = value;
            }
        }        

        #region TAM NGUYEN commend
        //public static Control ShowView(string MenuName, params Object[] args)
        //{
        //    Function ret = null;
        //    foreach (Function menu in Security.ListMenu3PL)
        //    {
        //        if (menu.Name == MenuName)
        //        {
        //            ret = menu;
        //            break;
        //        }
        //    }
        //    if (ret == null)
        //    {
        //        NotifyUserUtil.ShowErrorDialog("Menu name not found or you don't have permission to run this menu");
        //        return null;
        //    }
        //    else
        //    {
        //        return ShowView(ret.ID, args);
        //    }
        //}
        /// <summary>
        /// Shows the view corresponding with the menu.
        /// vinhvo Fix : return Control to use for return code
        /// </summary>
        /// <param name="menuId">The menu Id.</param>
        /// <exception cref="ArgumentException">There is no <see cref="TypeInfo"/> associated with the menu Id specified.</exception>
        public static Control ShowView(int menuId, params Object[] args)
        {
            Control control = null;

            lock (typeof(ViewManager))
            {
                if (_currentTypeInfo != null && _currentTypeInfo.Id == menuId)
                {
                    control = CreateControlInstance(_currentTypeInfo.Type, args);
                }
                else
                {
                    PharmacyPharnet.Core.Entity.TypeInfo info = _typeInfoCollection[menuId];

                    // the result from the indexer above may be null
                    if (info == null)
                    {
                        throw new ArgumentException(string.Format("There is no TypeInfo associated with the menu of Id {0}.", menuId), "menuId");
                    }

                    control = CreateControlInstance(info.Type, args);
                    _currentTypeInfo = info;
                }
            }

            if (control is ControlViewBase)
            {
                control.Tag = menuId;
                ShowView((ControlViewBase)control);
            }
            else if (control is DialogViewBase)
            {
                control.Tag = menuId;
                ShowView((DialogViewBase)control);
            }
            return control;
        }
        #endregion

        /// <summary>
        /// Get Control Type Name
        /// </summary>
        /// <param name="menuId"></param>
        /// <returns></returns>
        public static string GetControlType(int menuId)
        {
            try
            {
                PharmacyPharnet.Core.Entity.TypeInfo info = _typeInfoCollection[menuId];
                if (info != null && info.Type != null && info.Type.BaseType != null)
                    return info.Type.BaseType.FullName;
                else return string.Empty;
            }
            catch (Exception ex)
            {
                //NotifyUserUtil.ShowException(ex);
                return string.Empty;
            }
        }

        public static void ShowView(ControlViewBase controlView)
        {
            if (controlView == null || controlView.Disposing || controlView.IsDisposed)
            {
                return;
            }
            //2011/08/17 nghiemhoang upd stt
            //string featureTypeName = controlView.FeatureTypeName;
            string featureTypeName = string.Empty;
            featureTypeName = controlView.FeatureTypeName;
            //2011/08/17 nghiemhoang upd end

            lock (typeof(ViewManager))
            {
                if (!_ListWindows.ContainsKey(featureTypeName))
                {

                    //Register locking screen
                    //MDIController.RegisterFeatureTypeNameEditing(featureTypeName);
                    DialogViewBase frm = new DialogViewBase();
                    //CloseCustomizationControl(oldControl);
                    frm.Text = frm.Name = controlView.FeatureTypeName;

                    //Le Anh Phuong Add
                    //Set Title for Frm
                    string title = SR.Instance.GetString(controlView.FeatureTypeName);
                    if (title != null && title != string.Empty)
                    {
                        frm.Text = title;
                    }
                    //End Le Anh Phuong Add
                    frm.Controls.Add(controlView);
                    frm.Tag = controlView.Tag;
                    //In case, DialogViewBase is automatically created for UserControlViewBase
                    frm.ControlViewBase = controlView;
                    //In dialog process
                    if (_FeatureTypeNameInDialog != string.Empty)
                    {
                        frm.Height = controlView.Height + 30;
                        frm.Width = controlView.Width + 15;
                        ShowView(frm);
                    }
                    else
                    {
                        ViewChanged(controlView);
                    }

                }
                else
                {
                    ActivateView(_ListWindows[featureTypeName], controlView);
                }
            }
        }

        private static void ActivateView(IView currentView, IView newView)
        {
            DialogViewBase currentDialog = null;
            if (currentView is ControlViewBase)
            {
                currentDialog = (currentView as ControlViewBase).Parent as DialogViewBase;
            }
            else
            {
                currentDialog = currentView as DialogViewBase;
            }

            currentDialog.Activate();

            string keyRefreshActive = string.Format(KEY_REFRESH_ACTIVE, currentView.FeatureTypeName);
            //string refreshActiveValue = ConfigManager.AppConfig[keyRefreshActive];
            //if ((currentView is DialogViewBase && (refreshActiveValue == null || refreshActiveValue.ToUpper() != "FALSE")) || (currentView is ControlViewBase && refreshActiveValue != null && refreshActiveValue.ToUpper() == "TRUE")){
            try
            {
                //MDIController.InActiveRefresh = true;
                currentDialog.Close();

                if (currentDialog.IsClosed)
                {
                    if (newView is ControlViewBase)
                    {
                        ShowView(newView as ControlViewBase);
                    }
                    else
                    {
                        ShowView(newView as DialogViewBase);
                    }

                }
            }
            finally
            {
                //MDIController.InActiveRefresh = false;
            }
            //}            
        }

        private static void ViewChanged(IView view)
        {
            (view as Control).Disposed += new EventHandler(view_Disposed);
            _ListWindows.Add(view.FeatureTypeName, view);
            WindowEventArgs e = new WindowEventArgs(Pharmacy.Ultilities.Enums.WindowAction.Show, view);
            OnWindowChanged(e);

            DialogViewBase dialogView = null;
            if (view is ControlViewBase)
            {
                dialogView = ((view as ControlViewBase).Parent as DialogViewBase);
            }
            else
            {
                dialogView = view as DialogViewBase;
            }

            dialogView.Show();
            dialogView.FormClosing += new FormClosingEventHandler(dialogView_FormClosing);
        }

        private static void ViewChanged(IView view, string featureTypeName)
        {
            (view as Control).Disposed += new EventHandler(view_Disposed);
            _ListWindows.Add(featureTypeName, view);
            WindowEventArgs e = new WindowEventArgs(Pharmacy.Ultilities.Enums.WindowAction.Show, view);
            OnWindowChanged(e);

            DialogViewBase dialogView = null;
            if (view is ControlViewBase)
            {
                dialogView = ((view as ControlViewBase).Parent as DialogViewBase);
            }
            else
            {
                dialogView = view as DialogViewBase;
            }

            dialogView.Show();
            dialogView.FormClosing += new FormClosingEventHandler(dialogView_FormClosing);
        }
        /// <summary>
        /// Get Button Exist In Bar With Function Name
        /// </summary>
        /// <param name="bars"></param>
        /// <param name="FunctionName"></param>
        /// <returns></returns>
        private static BarButtonItem GetChildButtonInBars(IEnumerable<Bar> bars, string FunctionName)
        {
            foreach (Bar bar in bars)
            {
                if (bar.ItemLinks != null)
                {
                    foreach (BarItemLink barItemLink in bar.ItemLinks)
                    {
                        BarButtonItem barItem = barItemLink.Item as BarButtonItem;

                        if (barItem != null && barItem.Tag != null && barItem.Tag.ToString() == FunctionName)
                        {
                            //Remove buttons in bar, after that add these buttons again
                            //so that these buttons can be displayed in order of DisplayOrder.
                            bar.ItemLinks.Remove(barItemLink);
                            return barItem;
                        }
                    }
                }
            }
            return null;
        }

        private static void MoveButtonsToMainBar(Bar bar, Bar mainBar)
        {
            foreach (BarItemLink barItemLink in bar.ItemLinks)
            {
                BarButtonItem barItem = barItemLink.Item as BarButtonItem;
                mainBar.ItemLinks.Add(barItem);
            }
            bar.ItemLinks.Clear();
        }

        private static void ClearChildButtonInBarsNoPerm(IEnumerable<Bar> bars)
        {
            foreach (Bar bar in bars)
            {
                foreach (BarItemLink barItemLink in bar.ItemLinks)
                {
                    BarButtonItem barItem = barItemLink.Item as BarButtonItem;
                    if (barItem != null && !(barItem.Tag is Function))
                    {
                        barItem.Visibility = BarItemVisibility.Never;
                    }
                }
            }

        }

        private static IEnumerable<Bar> GetBar(Control dlg)
        {
            //Bar ret = null;
            //bool isFound = false;
            foreach (Control ctr in dlg.Controls)
            {
                if (ctr is BarDockControl)
                {
                    BarDockControl barDock = ctr as BarDockControl;
                    barDock.Manager.AllowCustomization = false;
                    barDock.Manager.AllowShowToolbarsPopup = false;
                    if (barDock.Dock == DockStyle.Top)
                    {
                        //List<Control> removeList = new List<Control>();
                        foreach (Control ctrDock in barDock.Controls)
                        {
                            if (ctrDock is DockedBarControl)
                            {

                                yield return ((DockedBarControl)ctrDock).Bar;
                            }
                        }
                        //foreach (Control removeCtr in removeList)
                        //{

                        //    barDock.Controls.Remove(removeCtr);
                        //}
                    }
                    else ctr.Visible = false;
                }
            }
            //return ret;
        }
        /// <summary>
        /// Shows the dialog view which inherit from the <see cref="DialogViewBase"/> class.
        /// </summary>
        /// <param name="dialogView">The dialog view will be shown.</param>
        public static void ShowView(DialogViewBase dialogView)
        {
            lock (typeof(ViewManager))
            {
                //Vinhvo Fix : Show Is Dialog If Dialog Type for 3PL
                string featureTypeName = null;
                string fullName = null;
                featureTypeName = dialogView.FeatureTypeName;
                fullName = SR.Instance.GetString(featureTypeName);

                if ((_FeatureTypeNameInDialog != string.Empty) || (fullName != null && fullName.ToUpper() == "TRUE"))
                {

                    //Register locking screen
                    //MDIController.RegisterFeatureTypeNameEditing(featureTypeName);
                    dialogView.FormClosing += new FormClosingEventHandler(dialogView_FormClosing);
                    dialogView.MaximizeBox = false;
                    dialogView.MinimizeBox = false;

                    //Start dialog process, then other next screens must be shown by Dialog
                    if (_FeatureTypeNameInDialog == string.Empty)
                    {
                        _FeatureTypeNameInDialog = featureTypeName;
                    }

                    dialogView.ShowDialog();
                    return;
                }
                if (!_ListWindows.ContainsKey(featureTypeName))
                {

                    //Register locking screen
                    //MDIController.RegisterFeatureTypeNameEditing(featureTypeName);
                    ViewChanged(dialogView);
                }
                else
                {
                    ActivateView(_ListWindows[featureTypeName], dialogView);
                }
            }
        }

        static void dialogView_FormClosing(object sender, FormClosingEventArgs e)
        {
            DialogViewBase dialogView = sender as DialogViewBase;
            dialogView.IsClosed = !e.Cancel;
            if (!e.Cancel)
            {
                if (dialogView.FeatureTypeName == _FeatureTypeNameInDialog)
                {
                    _FeatureTypeNameInDialog = string.Empty;
                }

                //In case, DialogViewBase is automatically created for UserControlViewBase
                IView view = dialogView.ControlViewBase;
                if (view == null)
                {
                    view = sender as IView;
                }
                MDIController.WindowClosing(view);
            }
        }

        static void view_Disposed(object sender, EventArgs e)
        {
            string featureTypeName = string.Empty;
            featureTypeName = (sender as IView).FeatureTypeName;
            
            if (_ListWindows.ContainsKey(featureTypeName))
            {

                WindowEventArgs eWindow = new WindowEventArgs(Pharmacy.Ultilities.Enums.WindowAction.Close, _ListWindows[featureTypeName]);
                OnWindowChanged(eWindow);

                _ListWindows.Remove(featureTypeName);

                OnWindowChanged(eWindow);
            }
        }

        /// <summary>
        /// Initializes the type infomation for all leaf menus. These types will be stored in the cache
        /// </summary>
        public static void InitializeTypeInfo()
        {
            Pharmacy.Data.Entity.Menu[] menus = new Security().ListPermitedMenus();

            _typeInfoCollection = new TypeInfoCollection();

            foreach (Pharmacy.Data.Entity.Menu aMenu in menus)
            {
                if (aMenu.TypeInfo != null) //&& aMenu.MenuType != 1
                {
                    try
                    {

                        Type objType =
                            AssemblyFactory.GetTypeFromAssembly(aMenu.TypeInfo.Assembly.Name,
                                                                          aMenu.TypeInfo.Name);

                        _typeInfoCollection.Add(new PharmacyPharnet.Core.Entity.TypeInfo(aMenu.ID, objType));

                    }
                    catch (Exception ex)
                    {
                        //NotifyUserUtil.ShowException(ex);
                    }
                }
            }
        }

        /// <summary>
        /// Creates the waiting dialog that use to display the progress information.
        /// You can use following code to make an auto-close wait dialog:
        /// using (ViewManager.CreateWaitDialog()) { }
        /// </summary>
        /// <author></author>
        /// <history>
        /// 2011.02.21 - ThangTran: added code to return WaitingDialog instance.
        /// 2011.02.22 - ThangTran: registered Disposed event to assign _waitingDialog to null.
        /// </history>
        public static WaitDialogForm CreateWaitDialog()
        {
            CloseWaitDialog();
            _waitingDialog = new WaitDialogForm("Loading...");
            _waitingDialog.FormBorderStyle = FormBorderStyle.Fixed3D;            
            _waitingDialog.AllowFormSkin = true;

            // register Disposed() so it will set _waitingDialog = null when being disposed
            _waitingDialog.Disposed +=
                delegate(object sender, EventArgs e)
                {
                    lock (typeof(ViewManager))
                    {
                        // if current active waiting dialog is being disposed
                        if (sender == _waitingDialog)
                        {
                            // remove from global variable
                            _waitingDialog = null;
                        }
                    }
                };

            return _waitingDialog;
        }

        /// <summary>
        /// Sets the text will be displayed on the waiting dialog.
        /// You can use following code to make an auto-close wait dialog:
        /// using (ViewManager.SetWaitDialogCaption(...)) { }
        /// </summary>
        /// <param name="title">The title will be displayed. This is an optional parameter.</param>
        /// <author></author>
        /// <history>
        /// 2011.02.17 - ThangTran: redirected to SetWaitDialogCaption(string title, string caption).
        /// 2011.02.21 - ThangTran: added code to return WaitingDialog instance.
        /// </history>
        public static WaitDialogForm SetWaitDialogCaption(string title)
        {
            return SetWaitDialogCaption(title, null);
        }

        /// <summary>
        /// Sets the  title and text will be displayed on the waiting dialog.
        /// You can use following code to make an auto-close wait dialog:
        /// using (ViewManager.SetWaitDialogCaption(...)) { }
        /// </summary>
        /// <param name="title">The title will be displayed. This is an optional parameter.</param>
        /// <param name="caption">The text will be displayed. This is an optional parameter.</param>
        /// <author></author>
        /// <history>
        /// 2011.02.17 - ThangTran: reformatted code, added more code to set title via reflection.
        /// 2011.02.21 - ThangTran: added code to return WaitingDialog instance.
        /// </history>
        public static WaitDialogForm SetWaitDialogCaption(string title, string caption)
        {
            // this lock ensures _waitingDialog.Caption is always a valid reference
            lock (typeof(ViewManager))
            {
                // create a new wait dialog if there is none available
                if (_waitingDialog == null)
                {
                    CreateWaitDialog();
                }

                // set title for the wait dialog, use reflection to set title because it was hidden
                // must set before the "set title" to use its update method
                ReflectionHelper.SetObjectValue(_waitingDialog, "title", title);

                // set title for the wait dialog
                _waitingDialog.Caption = caption;

                return _waitingDialog;
            }
        }

        /// <summary>
        /// Closes the wait dialog.
        /// </summary>
        /// <author></author>
        /// <history>
        /// 2011.02.21 - ThangTran: added try-catch to handle case the _waiting dialog is disposed.
        /// </history>
        public static void CloseWaitDialog()
        {
            if (_waitingDialog != null)
            {
                lock (typeof(ViewManager))
                {
                    try
                    {
                        // lock and double check to ensure _waitingDialog.Close is always a valid reference
                        if (_waitingDialog != null)
                        {
                            _waitingDialog.Close();
                            _waitingDialog = null;
                        }
                    }
                    catch (ObjectDisposedException)
                    {
                        // ignore this exception, assign _waitingDialog to null anyway
                        _waitingDialog = null;
                    }
                }
            }
        }


        #endregion

        #region Private methods

        /// <summary>
        /// Use reflection to create the control instance from the input type
        /// </summary>
        /// <param name="type">The type of the control</param>
        /// <returns>
        /// The <see cref="Control"/> object with the input type
        /// </returns>
        /// Last changed By vinhvo : add param when call constructure
        private static Control CreateControlInstance(Type type, params Object[] args)
        {
            if (!type.IsSubclassOf(typeof(Control)))
            {
                throw new ArgumentException(type.FullName + " doesn't inherit from the Control class");
            }
            Type[] paramType = null;
            if (args != null && args.Length != 0)
            {
                paramType = new Type[args.Length];
                for (int n = 0; n < args.Length; n++)
                {
                    paramType[n] = args[n].GetType();
                }
            }
            //Found Constructor With Param
            ConstructorInfo constructor = null;
            if (paramType != null)
            {
                constructor = type.GetConstructor(paramType);
            }
            else
            {
                constructor = type.GetConstructor(Type.EmptyTypes);
            }

            if (constructor == null)
            {
                throw new ArgumentException(type.FullName + " doesn't have a public constructor with empty parameters");
            }
            if (args != null && args.Length != 0)
            {
                return constructor.Invoke(args) as Control;
            }
            else
            {
                return constructor.Invoke(null) as Control;
            }
        }

        /// <summary>
        /// Disposes the current view.
        /// </summary>
        private static void DisposeCurrentView()
        {
            if (_currentControlView == null)
            {
                return;
            }
            try
            {
                // MessageBox.Show(_currentControlView.GetType().ToString());
                _currentControlView.Dispose();
            }
            catch (Exception ex)
            {
                //NotifyUserUtil.ShowException(ex);
            }
        }

        /// <summary>
        /// Get BaseView by Control
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        private static BaseView GetBaseViewByControl(Control control)
        {
            if (control == null)
            {
                return null;
            }

            foreach (Control cntl in control.Controls)
            {
                if (cntl is GridControl)
                {
                    return ((GridControl)cntl).MainView;
                }
            }
            return null;
        }

        /// <summary>
        /// Close Control
        /// </summary>
        /// <param name="control"></param>
        private static void CloseCustomizationControl(Control control)
        {
            if (control == null)
            {
                return;
            }
            foreach (Control ctrl in control.Controls)
            {
                CloseCustomizationControl(ctrl);
            }

            BaseView view = GetBaseViewByControl(control);
            if (view == null)
            {
                return;
            }

            foreach (BaseView bView in view.GridControl.Views)
            {
                if (bView is GridView)
                {
                    ((GridView)bView).DestroyCustomization();
                }
            }
        }

        #endregion Private methods
    }
}
